/*
 * Copyright (c) 2008-2009 Bill Whitacre http://rampancy.g0dsoft.com
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
*/

#ifndef RAT_PHYSICS_BODY
#define RAT_PHYSICS_BODY

#include "common.h"
#include "hull.h"
#include "vector.h"
#include "aabb.h"
#include "math_util.h"

struct rat_body;
struct rat_arbiter;
struct rat_constraint;
struct rat_spring;
struct rat_world;

#define rat_is_bullet_flag			0x1
#define rat_is_asleep_flag			0x2
#define rat_island_flag				0x4
#define rat_adjacency_filter_flag	0x8

extern rat_real rat_linear_sleep_tolerance;
extern rat_real rat_angular_sleep_tolerance;
extern rat_real rat_time_to_sleep;

typedef struct rat_body
{
	void *userdata;	// just some space to store something.  often a game actor this body's associated with for example.
	int filtertag;	// used in collision filters

	rat_real mass,inv_mass;
	rat_real moi,inv_moi;

	// bias values are instantanious and are used
	// in the iterative collision resolution.
	// the others are continuous.
	vector2 velocity,velocity_bias;
	rat_real omega,omega_bias;

	// torque is just angular force these are basically
	// the angular and linear components of the real
	// net force, which is more complex.
	vector2 force;
	rat_real torque;

	rat_real elasticity;
	rat_real friction;

	rat_hull *hull;

	unsigned int numarbiters;
	unsigned int numconsts;
	unsigned int numsprings;

	struct rat_arbiter **arbiters;
	struct rat_constraint **constraints;
	struct rat_spring **springs;

	int body_flags;
	rat_real sleep_timer;
} rat_body;

#ifdef __cplusplus
extern "C" {
#endif

rat_body *rat_body_create(rat_hull *hull,rat_real elasticity,rat_real friction,rat_real mass,rat_real moi);
void rat_body_destroy(rat_body *body);

void rat_body_set_is_bullet(rat_body *body,int is_bullet);
int rat_body_get_is_bullet(rat_body *body);

void rat_body_set_is_asleep(rat_body *body,int is_asleep);
int rat_body_get_is_asleep(rat_body *body);

void rat_body_set_island_marker(rat_body *body);
void rat_body_kill_island_marker(rat_body *body);
int rat_body_get_island_marker(rat_body *body);

void rat_body_enable_adjacency_filter(rat_body *body);
void rat_body_disable_adjacency_filter(rat_body *body);
int rat_body_is_adjacency_filter_enabled(rat_body *body);

void rat_body_set_filter_tag(rat_body *body,int tag);
int rat_body_get_filter_tag(rat_body *body);

void rat_body_set_mass(rat_body *body,rat_real mass);
void rat_body_set_moi(rat_body *body,rat_real moi);

rat_real rat_body_get_mass(rat_body *body);
rat_real rat_body_get_moi(rat_body *body);

vector2 rat_body_get_velocity(rat_body *body);
rat_real rat_body_get_omega(rat_body *body);

void rat_body_apply_offset_impulse(rat_body *body,vector2 impulse,vector2 offset);
void rat_body_apply_impulse(rat_body *body,vector2 impulse);
void rat_body_apply_torque(rat_body *body,rat_real torque);

void rat_body_apply_offset_bias_impulse(rat_body *body,vector2 impulse,vector2 offset);
void rat_body_apply_bias_impulse(rat_body *body,vector2 impulse);
void rat_body_apply_bias_torque(rat_body *body,rat_real torque);

void rat_body_apply_gravity(rat_body *body,vector2 gravity);
void rat_body_apply_force(rat_body *body,vector2 force,vector2 offset);
void rat_body_clear_force(rat_body *body);

void rat_body_integrate_velocity(rat_body *body,vector2 gravity,rat_real timestep,rat_real damping);
void rat_body_integrate_position_euler(rat_body *body,rat_real timestep);
void rat_body_integrate_position_rk4(rat_body *body,rat_real timestep);

#ifdef __cplusplus
}
#endif

// these are for internal use, the world object automatically uses these
void rat_body_add_arbiter(rat_body *body,struct rat_arbiter *arbiter);
void rat_body_remove_arbiter(rat_body *body,struct rat_arbiter *arbiter);

void rat_body_add_spring(rat_body *body,struct rat_spring *spring);
void rat_body_add_constraint(rat_body *body,struct rat_constraint *constraint);

void rat_body_remove_spring(rat_body *body,struct rat_spring *spring);
void rat_body_remove_constraint(rat_body *body,struct rat_constraint *constraint);

void rat_body_destroy_springs(rat_body *body,struct rat_world *world);
void rat_body_destroy_constraints(rat_body *body,struct rat_world *world);

#endif
